package com.javaee.wordtree.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.javaee.wordtree.entity.Message;
import com.javaee.wordtree.entity.MessageWithRagInfo;
import com.javaee.wordtree.entity.RagReplyResult;
import com.javaee.wordtree.entity.RagResponse;
import com.javaee.wordtree.entity.DeepseekResponse;
import com.javaee.wordtree.entity.User;
import com.javaee.wordtree.mapper.MessageMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.client.RestTemplate;
import org.springframework.http.ResponseEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 消息服务类
 */
@Service
public class MessageService extends ServiceImpl<MessageMapper, Message> {

    private static final Logger logger = LoggerFactory.getLogger(MessageService.class);

    @Resource
    private MessageMapper messageMapper;

    @Resource
    private ChatService chatService;

    @Resource
    private DeepseekService deepseekService;

    @Resource
    private UserService userService;

    @Resource
    private MessageRagService messageRagService;

    @Value("${rag.reply.api.url}")
    private String ragReplyApiUrl;

    @Value("${rag.similarity.threshold:0.05}")
    private double similarityThreshold;

    private final RestTemplate restTemplate = new RestTemplate();

    /**
     * 获取聊天的所有消息
     * 
     * @param chatId 聊天ID
     * @return 消息列表
     */
    public List<Message> getChatMessages(Integer chatId) {
        return messageMapper.findMessagesByChatId(chatId);
    }

    /**
     * 获取聊天的所有消息（包含RAG信息）
     * 
     * @param chatId 聊天ID
     * @return 包含RAG信息的消息列表
     */
    public List<MessageWithRagInfo> getChatMessagesWithRag(Integer chatId) {
        try {
            List<Message> messages = messageMapper.findMessagesByChatId(chatId);
            return messageRagService.convertToMessageWithRagInfoList(messages);
        } catch (Exception e) {
            logger.error("获取聊天{}的RAG消息时发生异常", chatId, e);
            throw new RuntimeException("获取RAG消息失败", e);
        }
    }

    /**
     * 保存用户消息并生成AI回复
     * 
     * @param chatId 聊天ID
     * @param text   用户发送的消息文本
     * @return 带有RAG信息的AI回复消息对象
     */
    @Transactional(rollbackFor = Exception.class)
    public MessageWithRagInfo saveMessageAndGenerateReply(String userId, Integer chatId, String text) {
        // 1. 保存用户消息
        Message userMessage = new Message();
        userMessage.setChatId(chatId);
        userMessage.setText(text);
        userMessage.setIsUser(true);
        userMessage.setCreatedTime(new Date());
        save(userMessage);

        // 2. 更新聊天的最后更新时间
        chatService.updateChatTime(chatId);

        User user = null;
        if (userId != null) {
            try {
                user = userService.getUserByID(userId);
            } catch (Exception e) {
                // 如果获取用户信息失败，记录日志但继续处理
                System.err.println("获取用户信息失败: " + e.getMessage());
            }
        } // 4. 生成AI回复和RAG信息
        RagReplyResult ragReplyResult = generateRagReply(text, user);

        // 5. 保存AI回复（包含RAG信息）
        MessageWithRagInfo aiMessageWithRag = new MessageWithRagInfo();
        aiMessageWithRag.setChatId(chatId);
        aiMessageWithRag.setText(ragReplyResult.getReplyText());
        aiMessageWithRag.setIsUser(false);
        aiMessageWithRag.setCreatedTime(new Date());
        aiMessageWithRag.setRagInfo(ragReplyResult.getRagInfo());

        // 转换为Message实体并保存到数据库
        Message aiMessage = messageRagService.convertToMessage(aiMessageWithRag);
        save(aiMessage);

        // 设置返回的消息ID
        aiMessageWithRag.setMessageId(aiMessage.getMessageId());

        // 6. 构建带有RAG信息的响应
        return aiMessageWithRag;
    }

    /**
     * 根据用户信息获取词书类型标签
     * 
     * @param user 用户信息
     * @return 词书类型标签字符串
     */
    private String getUserBookTypeLabel(User user) {
        if (user == null || user.getTargetBook() == null) {
            return "";
        }

        String targetBook = user.getTargetBook().toLowerCase();

        if (targetBook.contains("高考") || targetBook.contains("gaokao")) {
            return "该用户正在准备高考英语，请提供适合高中阶段的解答和词汇建议";
        } else if (targetBook.contains("考研") || targetBook.contains("kaoyan")) {
            return "该用户正在准备考研英语，请提供适合研究生入学考试难度的解答和词汇建议";
        } else if (targetBook.contains("CET-4") || targetBook.contains("CET4") || targetBook.contains("四级")) {
            return "该用户正在准备大学英语四级考试，请提供适合四级难度的解答和词汇建议";
        } else if (targetBook.contains("CET-6") || targetBook.contains("CET6") || targetBook.contains("六级")) {
            return "该用户正在准备大学英语六级考试，请提供适合六级难度的解答和词汇建议";
        } else if (targetBook.contains("IELTS") || targetBook.contains("雅思")) {
            return "该用户正在准备雅思考试，请提供适合雅思难度的解答和词汇建议，注重实用性和学术性";
        } else if (targetBook.contains("TOEFL") || targetBook.contains("托福")) {
            return "该用户正在准备托福考试，请提供适合托福难度的解答和词汇建议，注重学术英语应用";
        } else {
            // return "该用户没有明确的词书类型，请提供通用的英语学习建议和解答";
            return ""; // 如果没有匹配的词书类型，则返回空字符串
        }
    }

    /**
     * 生成RAG回复消息（新方法，先调用rag-answer检索，再发给deepseek）
     * 
     * @param userInput 用户输入
     * @param user      用户信息（可为空）
     * @return 生成的回复结果，包含回复文本和RAG信息
     */
    private RagReplyResult generateRagReply(String userInput, User user) {
        try {
            logger.info("开始处理RAG回复，用户问题: {}", userInput);

            // 1. 先调用rag-answer接口获取检索结果
            String ragUrl = ragReplyApiUrl + "/rag-answer?question=" + java.net.URLEncoder.encode(userInput, "UTF-8")
                    + "&topK=5";
            logger.info("调用RAG检索接口: {}", ragUrl);

            ResponseEntity<RagResponse> ragResponse = restTemplate.getForEntity(ragUrl, RagResponse.class);
            RagResponse ragResult = ragResponse.getBody();

            logger.info("RAG检索结果: count={}", ragResult != null ? ragResult.getCount() : "null");

            // 2. 判断检索结果是否有效，如果无效则设为空列表
            List<RagResponse.RagResult> filteredResults;
            int originalCount = 0;
            if (ragResult == null || ragResult.getCount() == null || ragResult.getCount() <= 0) {
                filteredResults = new ArrayList<>();
            } else {
                originalCount = ragResult.getCount();
                // 3. 过滤低分数的结果
                filteredResults = ragResult.getResults().stream()
                        .filter(result -> result.getSimilarity() >= similarityThreshold)
                        .collect(Collectors.toList());
            }

            logger.info("过滤后的RAG结果数量: {}", filteredResults.size());

            // 4. 构建RAG增强信息
            MessageWithRagInfo.RagEnhancementInfo ragInfo = buildRagEnhancementInfo(
                    originalCount, filteredResults, similarityThreshold);

            // 5. 构建给DeepSeek的prompt - 使用Builder模式
            String userBookType = getUserBookTypeLabel(user);
            logger.info("用户词书标签: {}", userBookType.isEmpty() ? "无标签" : userBookType);

            String prompt = PromptBuilder.create()
                    .withUserInput(userInput)
                    .withUserLabel(userBookType)
                    .withRagResults(filteredResults)
                    .build();

            // 6. 调用DeepSeek API
            logger.info("开始调用DeepSeek API生成回复");
            DeepseekResponse deepseekResponse = deepseekService.callDeepseekApi(prompt)
                    .block(); // 同步等待结果

            if (deepseekResponse != null && deepseekResponse.getChoices() != null
                    && !deepseekResponse.getChoices().isEmpty()) {
                String aiReply = deepseekResponse.getChoices().get(0).getMessage().getContent();
                logger.info("DeepSeek API回复成功，回复长度: {}", aiReply.length());
                return RagReplyResult.of(aiReply, ragInfo);
            }

            logger.warn("DeepSeek API回复失败或返回空内容");
            return RagReplyResult.of("AI回复失败，请稍后再试。", ragInfo);

        } catch (Exception e) {
            logger.error("生成RAG回复时出现异常: {}", e.getMessage(), e);
            return RagReplyResult.withoutRag("AI服务暂时不可用，请稍后再试。");
        }
    }

    /**
     * 构建RAG增强信息
     * 
     * @param originalCount   原始检索结果数量
     * @param filteredResults 过滤后的结果
     * @param threshold       相似度阈值
     * @return RAG增强信息
     */
    private MessageWithRagInfo.RagEnhancementInfo buildRagEnhancementInfo(
            int originalCount, List<RagResponse.RagResult> filteredResults, double threshold) {

        MessageWithRagInfo.RagEnhancementInfo ragInfo = new MessageWithRagInfo.RagEnhancementInfo();

        // 设置基本信息
        ragInfo.setBasedOnRag(!filteredResults.isEmpty());
        ragInfo.setRagCount(originalCount);
        ragInfo.setValidRagCount(filteredResults.size());
        ragInfo.setSimilarityThreshold(threshold);

        if (!filteredResults.isEmpty()) {
            // 计算相似度统计
            double totalSimilarity = 0.0;
            double maxSim = filteredResults.get(0).getSimilarity();
            double minSim = filteredResults.get(0).getSimilarity();

            List<MessageWithRagInfo.RagResultSummary> summaries = new ArrayList<>();

            for (RagResponse.RagResult result : filteredResults) {
                double similarity = result.getSimilarity();
                totalSimilarity += similarity;
                maxSim = Math.max(maxSim, similarity);
                minSim = Math.min(minSim, similarity);

                // 创建摘要信息
                MessageWithRagInfo.RagResultSummary summary = new MessageWithRagInfo.RagResultSummary();
                summary.setSimilarity(similarity);

                // 截取问题摘要（前50个字符）
                String question = result.getQuestion();
                summary.setQuestionSummary(question != null && question.length() > 50
                        ? question.substring(0, 50) + "..."
                        : question);

                // 截取答案摘要（前100个字符）
                String answer = result.getAnswer();
                summary.setAnswerSummary(answer != null && answer.length() > 100
                        ? answer.substring(0, 100) + "..."
                        : answer);

                summaries.add(summary);
            }

            ragInfo.setAverageSimilarity(totalSimilarity / filteredResults.size());
            ragInfo.setMaxSimilarity(maxSim);
            ragInfo.setMinSimilarity(minSim);
            ragInfo.setRagResults(summaries);
        } else {
            ragInfo.setAverageSimilarity(0.0);
            ragInfo.setMaxSimilarity(0.0);
            ragInfo.setMinSimilarity(0.0);
        }

        return ragInfo;
    }
}
